package ri.core;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.Collector;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopScoreDocCollector;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.store.SimpleFSDirectory;
import org.apache.lucene.util.Version;

/**
 * Todos os usuarios e os dados para o SR estao mapeados como Documentos e armazenados no Corpus
 * Padrao SINGLETON.
 * @author Delano, Izabela, Savyo, Nata
 *
 */

public class Corpus {
	
	private Directory directory;
	private Analyzer analyzer;
	private static Corpus instance;
	
	public static final Version VERSION = Version.LUCENE_31;
	public static final String NAME_FIELD_MENCOES_FEITAS = "mencoesFeitas";
	public static final String NAME_FIELD_MENCOES_RECEBIDAS = "mencoesRecebidas";
	public static final String NAME_FIELD_USERNAME = "username";
	public static final String NAME_FIELD_DATE = "date";
	
	public static final String PATH_FILE = "file";
	
	public static Corpus getInstance() {
		if(instance == null)
			instance = new Corpus();
		return instance;
	}
	
	public Corpus() {
		try {
			directory = new SimpleFSDirectory(new File(PATH_FILE));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		analyzer = new StandardAnalyzer(VERSION);
		
	}
	
	public IndexWriter getIndexWriter(){
		IndexWriterConfig indexconfig = new IndexWriterConfig(VERSION, analyzer);
		IndexWriter indexWriter = null;
		try {
			indexWriter = new IndexWriter(directory, indexconfig);
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (LockObtainFailedException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return indexWriter;
	}
	
	public void updateDatas(String username, List<String> metionsFeitas, List<String> mencoesRecebidas, Date date){
		HashMap<String, String> recebidas = new HashMap<String, String>();
		HashMap<String, String> feitas = new HashMap<String, String>();
		
		
		for(String s : metionsFeitas){
			if(recebidas.get(s) == null){
				recebidas.put(s, username);
			}else{
				recebidas.put(s, recebidas.get(s) + " " + username);
			}
		}
		
		for(String s : mencoesRecebidas){
			if(feitas.get(s) == null){
				feitas.put(s, username);
			}else{
				feitas.put(s, feitas.get(s) + " " + username);
			}
		}
		
		HashSet<String> users = new HashSet<String>();
		users.addAll(recebidas.keySet());
		users.addAll(feitas.keySet());
		
		addDataToUser(username, "", "", date.toGMTString());
		
		for(String user : users){
			addDataToUser(user, feitas.get(user), recebidas.get(user), "");
		}
		
	}
	
	public Date lastUpdate(String username){
		Document user = getDocument(username);
		if(user != null){
			return new Date(Date.parse(user.get(NAME_FIELD_DATE)));
		}
		return null;
	}
	
	private void addDataToUser(String username, String metionsFeitas, String metionsRecebidas, String date){
		Document user = getDocument(username);
		String metionsFeitasLast = "";
		String metionsRecebidasLast = "";
		String dateLast = "";
		if(user != null){
			metionsFeitasLast = user.get(NAME_FIELD_MENCOES_FEITAS);
			metionsRecebidasLast = user.get(NAME_FIELD_MENCOES_RECEBIDAS);
			dateLast = user.get(NAME_FIELD_DATE);
			deleteDocument(username);
		}
		
		if(!date.equalsIgnoreCase("")){
			dateLast = date;
		}
		
		metionsFeitasLast += metionsFeitas == null ? "" : " " + metionsFeitas;
		metionsRecebidasLast += metionsRecebidas == null ? "" : " " + metionsRecebidas;
		
		metionsFeitasLast = metionsFeitasLast.trim();
		metionsRecebidasLast = metionsRecebidasLast.trim();
		addDocument(username, metionsFeitasLast, metionsRecebidasLast, dateLast);
		
	}
	
	private void addDocument(String username, String mencoesFeitas, String mencoesRecebidas, String date){
		Document doc = new Document();
		doc.add(new Field(NAME_FIELD_USERNAME, username, Field.Store.YES, Field.Index.ANALYZED));
		doc.add(new Field(NAME_FIELD_MENCOES_FEITAS, mencoesFeitas, Field.Store.YES, Field.Index.ANALYZED));
		doc.add(new Field(NAME_FIELD_MENCOES_RECEBIDAS, mencoesRecebidas, Field.Store.YES, Field.Index.ANALYZED));
		doc.add(new Field(NAME_FIELD_DATE, date, Field.Store.YES, Field.Index.NO));
		IndexWriter index = getIndexWriter();
		try {
			index.addDocument(doc);
			index.optimize();
			index.close();
		} catch (CorruptIndexException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void searchTF(String field, String query, Collector results){
		try {
			IndexReader re = IndexReader.open(directory);
			IndexSearcher s = new IndexSearcher(re);
			s.setSimilarity(new SimilarityTF());
			Query q = new QueryParser(VERSION, field, analyzer).parse(query);
			
			s.search(q, results);
		} catch (CorruptIndexException e) {
		} catch (IOException e) {
		} catch (ParseException e) {
		}
		
	}
	
	public void search(String field, String query, Collector results){
		try {
			IndexReader re = IndexReader.open(directory);
			IndexSearcher s = new IndexSearcher(re);
			Query q = new QueryParser(VERSION, field, analyzer).parse(query);
			
			s.search(q, results);
		} catch (CorruptIndexException e) {
		} catch (IOException e) {
		} catch (ParseException e) {
		}
		
	}
	
	public IndexReader getIndexReader(){
		IndexReader index = null;
		try{
			index = IndexReader.open(directory);
		} catch (CorruptIndexException e) {
			
		} catch (IOException e) {
			
		}
		return index;
	}
	
	private Document getDocument(String username){
		
		Document doc = null;
		
		TopScoreDocCollector r = TopScoreDocCollector.create(1, true);
		search(NAME_FIELD_USERNAME, username, r);
		IndexReader re = getIndexReader();
		ScoreDoc[] score = r.topDocs().scoreDocs;
			if(score.length > 0)
				try {
					doc = re.document(score[0].doc);
				} catch (CorruptIndexException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		
		
		return doc;
	}
	
	private void deleteDocument(String username){
		try {
			Query q = new QueryParser(VERSION, NAME_FIELD_USERNAME, analyzer).parse(username);
			IndexWriter index = getIndexWriter();
			index.deleteDocuments(q);
			index.close();
			
		} catch (CorruptIndexException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}
